// @ts-nocheck
import {Puerts, UnityEngine} from "csharp";
import {EventEmitter} from "./eventEmitter";
import {Component} from "./component";
import {$typeof} from "puerts";
import Time = UnityEngine.Time;

export class ComponentMgr {
    public static TICK_UPDATE = 1;//: string = "TICK_UPDATE";
    public static TICK_LATEUPDATE = 2;//: string = "TICK_LATEUPDATE";
    public static TICK_FIXEDUPDATE = 3;//: string = "TICK_FIXEDUPDATE";
    public static readonly Instance: ComponentMgr = new ComponentMgr();
    private readonly emitter: EventEmitter = new EventEmitter();

    map: { [key: number]: Component[] } = {};

    Update() {
        this.emitter.emit(ComponentMgr.TICK_UPDATE,Time.deltaTime);
    }

    LateUpdate() {
        this.emitter.emit(ComponentMgr.TICK_LATEUPDATE,Time.deltaTime);
    }

    FixedUpdate() {
        this.emitter.emit(ComponentMgr.TICK_FIXEDUPDATE,Time.fixedDeltaTime);
    }
    
    On(hashCode: number, comp: Component) {
        if (this.map[hashCode] == null)
            this.map[hashCode] = [];
        this.map[hashCode].push(comp);
        //注册事件
        if(comp.Update)            
            this.emitter.on(ComponentMgr.TICK_UPDATE,comp.Update)
        if(comp.LateUpdate)            
            this.emitter.on(ComponentMgr.TICK_LATEUPDATE,comp.LateUpdate)
        if(comp.FixedUpdate)            
            this.emitter.on(ComponentMgr.TICK_FIXEDUPDATE,comp.FixedUpdate)
    }

    Off(hashCode: number, comp: Component) {
        let comps:Component[] = this.map[hashCode];
        for (let i = 0, length = comps.length; i < length; i++) {
            if (comps[i] == comp) {
                delete this.map[hashCode][i];
                this.map[hashCode][i] = null;
                //移除事件
                if(comp.Update)                    
                    this.emitter.off(ComponentMgr.TICK_UPDATE,comp.Update)
                if(comp.LateUpdate)                    
                    this.emitter.off(ComponentMgr.TICK_LATEUPDATE,comp.LateUpdate)
                if(comp.FixedUpdate)                    
                    this.emitter.off(ComponentMgr.TICK_FIXEDUPDATE,comp.FixedUpdate)
                return;
            }
        }
    }

    GetComponent<T extends Component>(go: UnityEngine.GameObject | UnityEngine.Transform, compType: { prototype: T }): T {
        if (go instanceof UnityEngine.Transform) {
            go = go.gameObject;
        }
        let components = this.GetComponents(go, compType);
        if (components.length <= 0) return null;
        return <T>components[0];
    }

    GetComponents<T extends Component>(go: UnityEngine.GameObject | UnityEngine.Transform, compType: { prototype: T }): T[] {
        let hashCode = go.GetHashCode();
        if (this.map[hashCode] == null || this.map[hashCode].length <= 0) return null;
        let components = this.map[hashCode].filter(comp => comp instanceof <typeof Component><unknown>compType);
        return <T[]>components;
    }

    Initialize(behaviour: Puerts.JsManager) {
        behaviour._jsUpdate = () => this.Update();
        behaviour._jsLateUpdate = () => this.LateUpdate();
        behaviour._jsFixUpdate = () => this.FixedUpdate();
    }
}

export function init(behaviour: Puerts.JsManager) {
    ComponentMgr.Instance.Initialize(behaviour)
}
